package com.googlecode.gwt.test.internal.patchers;
import com.google.gwt.core.client.JavaScriptObject;
import com.google.gwt.core.client.JsonUtils;
import com.googlecode.gwt.test.exceptions.GwtTestException;
import com.googlecode.gwt.test.exceptions.GwtTestJSONException;
import com.googlecode.gwt.test.patchers.PatchClass;
import com.googlecode.gwt.test.patchers.PatchMethod;
import com.googlecode.gwt.test.utils.JavaScriptObjects;
import org.apache.commons.lang3.StringEscapeUtils;
import org.codehaus.jackson.JsonFactory;
import org.codehaus.jackson.JsonParseException;
import org.codehaus.jackson.JsonParser;
import org.codehaus.jackson.JsonToken;
import java.io.IOException;
import java.util.List;
@PatchClass(JsonUtils.class)
class JsonUtilsPatcher {
private static JsonFactory factory;
@PatchMethod
public static <T extends JavaScriptObject> T safeEval(String json) {
return eval(json);
}
@PatchMethod
public static <T extends JavaScriptObject> T unsafeEval(String json) {
return eval(json);
}
@PatchMethod
static String escapeValue(String toEscape) {
return "\"" + StringEscapeUtils.escapeEcmaScript(toEscape) + "\"";
}
@PatchMethod
static boolean hasJsonParse() {
return true;
}
@PatchMethod
static JavaScriptObject initEscapeTable() {
return null;
}
private static <T extends JavaScriptObject> T eval(String json) {
JsonParser jp = null;
try {
jp = getFactory().createJsonParser(json);
jp.nextToken(); // will return JsonToken.START_OBJECT (verify?)
return extractJso(json, jp.getCurrentToken(), jp).<T>cast();
} catch (Exception e) {
if (e instanceof GwtTestException) {
throw (GwtTestException) e;
}
throw new GwtTestJSONException("Error while parsing JSON string '" + json + "'", e);
} finally {
if (jp != null) {
try {
// ensure resources get cleaned up timely and properly
jp.close();
} catch (IOException e) {
// should never happen
}
}
}
}
private static JavaScriptObject extractArray(String json, JsonToken currentToken, JsonParser jp)
throws GwtTestJSONException, IOException {
JavaScriptObject jsArray = JavaScriptObject.createArray();
List<Object> list = JsArrayHelper.getWrappedList(jsArray);
while ((currentToken = jp.nextToken()) != JsonToken.END_ARRAY) {
Object value = extractValue(json, jp.getCurrentToken(), jp);
list.add(value);
}
return jsArray;
}
private static JavaScriptObject extractJso(String json, JsonToken currentToken, JsonParser jp)
throws JsonParseException, GwtTestJSONException, IOException {
JavaScriptObject jso = JavaScriptObject.createObject();
while ((currentToken = jp.nextToken()) != JsonToken.END_OBJECT) {
JavaScriptObjects.setProperty(jso, jp.getCurrentName(),
extractValue(json, jp.nextToken(), jp));
}
return jso;
}
private static Object extractValue(String json, JsonToken currentToken, JsonParser jp)
throws GwtTestJSONException, IOException {
switch (currentToken) {
case VALUE_NULL:
return null;
case VALUE_STRING:
return jp.getText();
case VALUE_NUMBER_INT:
return jp.getIntValue();
case VALUE_NUMBER_FLOAT:
return jp.getFloatValue();
case VALUE_TRUE:
return true;
case VALUE_FALSE:
return false;
case START_ARRAY:
return extractArray(json, currentToken, jp);
case START_OBJECT:
return extractJso(json, currentToken, jp);
default:
throw new GwtTestJSONException("Error while parsing JSON string '" + json
+ "' : gwt-test-utils does not handle token '" + jp.getText() + "', line "
+ jp.getTokenLocation().getLineNr() + " column "
+ jp.getTokenLocation().getColumnNr());
}
}
private static JsonFactory getFactory() {
if (factory == null) {
factory = new JsonFactory();
factory.configure(JsonParser.Feature.ALLOW_COMMENTS, true);
factory.configure(JsonParser.Feature.ALLOW_UNQUOTED_FIELD_NAMES, true);
factory.configure(JsonParser.Feature.ALLOW_SINGLE_QUOTES, true);
factory.configure(JsonParser.Feature.ALLOW_BACKSLASH_ESCAPING_ANY_CHARACTER, true);
factory.configure(JsonParser.Feature.ALLOW_UNQUOTED_CONTROL_CHARS, true);
factory.configure(JsonParser.Feature.ALLOW_UNQUOTED_CONTROL_CHARS, true);
factory.configure(JsonParser.Feature.ALLOW_NUMERIC_LEADING_ZEROS, true);
}
return factory;
}
}